<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>并发编程三大核心问题 | JavaPool</title>
    <meta name="generator" content="VuePress 1.9.2">
    <link rel="icon" href="/img/favicon.ico">
    <meta name="description" content="java pool icu">
    <meta name="keywords" content="vuepress,theme,blog,vdoing">
    <meta name="theme-color" content="#a1cd00">
    
    <link rel="preload" href="/assets/css/0.styles.6964efbe.css" as="style"><link rel="preload" href="/assets/js/app.c5f14b06.js" as="script"><link rel="preload" href="/assets/js/2.0bb8723e.js" as="script"><link rel="preload" href="/assets/js/8.165e4749.js" as="script"><link rel="prefetch" href="/assets/js/10.56cf0803.js"><link rel="prefetch" href="/assets/js/11.3f64ae04.js"><link rel="prefetch" href="/assets/js/12.02afd2cb.js"><link rel="prefetch" href="/assets/js/13.635b7092.js"><link rel="prefetch" href="/assets/js/14.f10556e8.js"><link rel="prefetch" href="/assets/js/15.27d8470a.js"><link rel="prefetch" href="/assets/js/16.70efe620.js"><link rel="prefetch" href="/assets/js/17.a79eaec6.js"><link rel="prefetch" href="/assets/js/18.aa4c8485.js"><link rel="prefetch" href="/assets/js/19.d98d039e.js"><link rel="prefetch" href="/assets/js/20.31b4dba4.js"><link rel="prefetch" href="/assets/js/21.c5f5372e.js"><link rel="prefetch" href="/assets/js/3.36e473cd.js"><link rel="prefetch" href="/assets/js/4.862e5a4f.js"><link rel="prefetch" href="/assets/js/5.81a4a7b6.js"><link rel="prefetch" href="/assets/js/6.634b1bae.js"><link rel="prefetch" href="/assets/js/7.00cec9d7.js"><link rel="prefetch" href="/assets/js/9.5122111b.js">
    <link rel="stylesheet" href="/assets/css/0.styles.6964efbe.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/img/logo.png" alt="JavaPool" class="logo"> <span class="site-name can-hide">JavaPool</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <!----></div></header> <div class="sidebar-mask"></div> <div class="sidebar-hover-trigger"></div> <aside class="sidebar" style="display:none;"><!----> <!---->  <ul class="sidebar-links"><li><a href="/pages/f0d781/" aria-current="page" class="active sidebar-link">并发编程三大核心问题</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level2"><a href="/pages/f0d781/#可见性" class="sidebar-link">可见性</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f0d781/#可见性是什么" class="sidebar-link">可见性是什么？</a></li><li class="sidebar-sub-header level3"><a href="/pages/f0d781/#为什么会有可见性问题" class="sidebar-link">为什么会有可见性问题？</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f0d781/#原子性" class="sidebar-link">原子性</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f0d781/#原子性是什么" class="sidebar-link">原子性是什么？</a></li><li class="sidebar-sub-header level3"><a href="/pages/f0d781/#为什么会有原子性问题" class="sidebar-link">为什么会有原子性问题？</a></li><li class="sidebar-sub-header level3"><a href="/pages/f0d781/#线程切换带来原子性问题。" class="sidebar-link">线程切换带来原子性问题。</a></li><li class="sidebar-sub-header level3"><a href="/pages/f0d781/#原子性问题举例" class="sidebar-link">原子性问题举例</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f0d781/#有序性" class="sidebar-link">有序性</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f0d781/#有序性问题举例" class="sidebar-link">有序性问题举例</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f0d781/#总结" class="sidebar-link">总结</a></li></ul></li><li><a href="/pages/f94dea/" class="sidebar-link">深入理解线程池</a></li><li><a href="/pages/6c4806/" class="sidebar-link">线程池</a></li><li><a href="/pages/76d299/" class="sidebar-link">并发编程-FutureTask</a></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="articleInfo-wrap" data-v-06225672><div class="articleInfo" data-v-06225672><ul class="breadcrumbs" data-v-06225672><li data-v-06225672><a href="/" title="首页" class="iconfont icon-home router-link-active" data-v-06225672></a></li> <li data-v-06225672><a href="/categories/?category=%E5%B9%B6%E5%8F%91%E5%A4%9A%E7%BA%BF%E7%A8%8B" title="分类" data-v-06225672>并发多线程</a></li></ul> <div class="info" data-v-06225672><div title="作者" class="author iconfont icon-touxiang" data-v-06225672><a href="https://mp.weixin.qq.com/s?__biz=MzAxMjEwMzQ5MA==&amp;mid=2448888446&amp;idx=2&amp;sn=2d341878615e238eb572e855199b9a7e&amp;scene=21#wechat_redirect" target="_blank" title="作者" class="beLink" data-v-06225672>java进阶架构师</a></div> <div title="创建时间" class="date iconfont icon-riqi" data-v-06225672><a href="javascript:;" data-v-06225672>2021-12-27</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-title">目录</div> <div class="right-menu-content"></div></div></div> <h1><img src="">并发编程三大核心问题<span class="title-tag">转载</span></h1> <!----> <div class="theme-vdoing-content content__default"><h1 id="并发编程三大问题-原子性、可见性、有序性。"><a href="#并发编程三大问题-原子性、可见性、有序性。" class="header-anchor">#</a> 并发编程三大问题：原子性、可见性、有序性。</h1> <h2 id="可见性"><a href="#可见性" class="header-anchor">#</a> 可见性</h2> <h3 id="可见性是什么"><a href="#可见性是什么" class="header-anchor">#</a> 可见性是什么？</h3> <p>一个线程对共享变量的修改，另外一个线程能够立刻看到，我们称为可见性。</p> <h3 id="为什么会有可见性问题"><a href="#为什么会有可见性问题" class="header-anchor">#</a> 为什么会有可见性问题？</h3> <p>对于如今的多核处理器，每颗CPU都有自己的缓存，而缓存仅仅对它所在的处理器可见，CPU缓存与内存的数据不容易保证一致。</p> <p>为了避免处理器停顿下来等待向内存写入数据而产生的延迟，处理器使用写缓冲区来临时保存向内存写入的数据。写缓冲区合并对同一内存地址的多次写，并以批处理的方式刷新，也就是说<strong>写缓冲区不会即时将数据刷新到主内存中</strong>。</p> <p><strong>缓存不能及时刷新导致了可见性问题。</strong></p> <p><strong>可见性问题举例</strong></p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">increase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        a<span class="token operator">++</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">final</span> <span class="token class-name">Test</span> test <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">10</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> <span class="token number">1000</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
                        test<span class="token punctuation">.</span><span class="token function">increase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>

                <span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">activeCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 保证前面的线程都执行完</span>
            <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token keyword">yield</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>test<span class="token punctuation">.</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>目的：10个线程将inc加到10000。</p> <p>结果：每次运行，得到的结果都小于10000。</p> <p>原因分析：</p> <p><img src="" alt=""></p> <p>假设线程1和线程2同时开始执行，那么第一次都会将a=0 读到各自的CPU缓存里，线程1执行a++之后a=1，但是<strong>此时线程2是看不到线程1中a的值的</strong>，所以线程2里a=0，执行a++后a=1。
``
线程1和线程2各自CPU缓存里的值都是1，之后线程1和线程2都会将自己缓存中的a=1写入内存，导致内存中a=1，而不是我们期望的2。所以导致最终 a 的值都是小于 10000 的。这就是缓存的可见性问题。</p> <h2 id="原子性"><a href="#原子性" class="header-anchor">#</a> 原子性</h2> <h3 id="原子性是什么"><a href="#原子性是什么" class="header-anchor">#</a> 原子性是什么？</h3> <p>把一个或者多个操作在 CPU 执行的过程中不被中断的特性称为原子性。</p> <p>在并发编程中，原子性的定义不应该和事务中的原子性（一旦代码运行异常可以回滚）一样。应该理解为：一段代码，或者一个变量的操作，在一个线程没有执行完之前，不能被其他线程执行。</p> <h3 id="为什么会有原子性问题"><a href="#为什么会有原子性问题" class="header-anchor">#</a> 为什么会有原子性问题？</h3> <p>线程是CPU调度的基本单位。CPU会根据不同的调度算法进行线程调度，将时间片分派给线程。当一个线程获得时间片之后开始执行，在时间片耗尽之后，就会失去CPU使用权。多线程场景下，由<strong>于时间片在线程间轮换，就会发生原子性问题</strong>。</p> <p>如：对于一段代码，一个线程还没执行完这段代码但是时间片耗尽，在等待CPU分配时间片，此时其他线程可以获取执行这段代码的时间片来执行这段代码，导致多个线程同时执行同一段代码，也就是原子性问题。</p> <h3 id="线程切换带来原子性问题。"><a href="#线程切换带来原子性问题。" class="header-anchor">#</a> <strong>线程切换带来原子性问题。</strong></h3> <p>在Java中，对基本数据类型的变量的读取和赋值操作是原子性操作，即这些操作是不可被中断的，要么执行，要么不执行。</p> <div class="language-java extra-class"><pre class="language-java"><code>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>		<span class="token comment">// 原子性操作</span>
j <span class="token operator">=</span> i<span class="token punctuation">;</span>		<span class="token comment">// 不是原子性操作，包含了两个操作：读取i，将i值赋值给j</span>
i<span class="token operator">++</span><span class="token punctuation">;</span> 			<span class="token comment">// 不是原子性操作，包含了三个操作：读取i值、i + 1 、将+1结果赋值给i</span>
i <span class="token operator">=</span> j <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>		<span class="token comment">// 不是原子性操作，包含了三个操作：读取j值、j + 1 、将+1结果赋值给i</span>

</code></pre></div><h3 id="原子性问题举例"><a href="#原子性问题举例" class="header-anchor">#</a> 原子性问题举例</h3> <p>还是上文中的代码，10个线程将inc加到10000。假设在保证可见性的情况下，仍然会因为原子性问题导致执行结果达不到预期。为方便看，把代码贴到这里：</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Test</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">increase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        a<span class="token operator">++</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">final</span> <span class="token class-name">Test</span> test <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">10</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> <span class="token number">1000</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
                        test<span class="token punctuation">.</span><span class="token function">increase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>

                <span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">activeCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 保证前面的线程都执行完</span>
            <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token keyword">yield</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>test<span class="token punctuation">.</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>目的：10个线程将inc加到10000。
结果：每次运行，得到的结果都小于10000。</p> <p>原因分析：</p> <blockquote><p>首先来看a++操作，其实包括三个操作：</p> <p>①读取a=0;</p> <p>②计算0+1=1;</p> <p>③将1赋值给a;</p> <p>保证a++的原子性，就是保证这三个操作在一个线程没有执行完之前，不能被其他线程执行。</p></blockquote> <p>实际执行时序图如下：</p> <p><img src="/assets/img/20210713002.576a5207.png" alt=""></p> <p>关键一步：线程2在读取a的值时，线程1还没有完成a=1的赋值操作，导致线程2的计算结果也是a=1。</p> <p><strong>问题在于没有保证a++操作的原子性</strong>。如果保证a++的原子性，线程1在执行完三个操作之前，线程2不能执行a++，那么就可以保证在线程2执行a++时，读取到a=1，从而得到正确的结果。</p> <h2 id="有序性"><a href="#有序性" class="header-anchor">#</a> 有序性</h2> <p>有序性：程序执行的顺序按照代码的先后顺序执行。</p> <p>编译器为了优化性能，有时候会改变程序中语句的先后顺序。例如程序中：“a=6；b=7；”编译器优化后可能变成“b=7；a=6；”，在这个例子中，编译器调整了语句的顺序，但是不影响程序的最终结果。不过有时候编译器及解释器的优化可能导致意想不到的Bug。</p> <h3 id="有序性问题举例"><a href="#有序性问题举例" class="header-anchor">#</a> 有序性问题举例</h3> <p>Java中的一个经典的案例：利用双重检查创建单例对象</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Singleton</span> <span class="token punctuation">{</span>
  <span class="token keyword">static</span> <span class="token class-name">Singleton</span> instance<span class="token punctuation">;</span>
  <span class="token keyword">static</span> <span class="token class-name">Singleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>instance <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">synchronized</span><span class="token punctuation">(</span><span class="token class-name">Singleton</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>instance <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
          instance <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Singleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> instance<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>在获取实例getInstance()的方法中，我们首先判断 instance是否为空，如果为空，则锁定 Singleton.class并再次检查instance是否为空，如果还为空则创建Singleton的一个实例。
看似很完美，既保证了线程完全的初始化单例，又经过判断instance为null时再用synchronized同步加锁。但是还有问题！</p> <p><code>instance = new Singleton();</code> 创建对象的代码，分为三步：
①分配内存空间
②初始化对象Singleton
③将内存空间的地址赋值给instance</p> <p>但是这三步经过重排之后：
①分配内存空间
②将内存空间的地址赋值给instance
③初始化对象Singleton</p> <p>会导致什么结果呢？</p> <p>线程A先执行getInstance()方法，当执行完指令②时恰好发生了线程切换，切换到了线程B上；如果此时线程B也执行getInstance()方法，那么线程B在执行第一个判断时会发现instance!=null，所以直接返回instance，而此时的instance是没有初始化过的，如果我们这个时候访问instance的成员变量就可能触发空指针异常。</p> <p>执行时序图：</p> <p><img src="" alt=""></p> <h2 id="总结"><a href="#总结" class="header-anchor">#</a> 总结</h2> <p>并发编程的本质就是解决三大问题：原子性、可见性、有序性。</p> <p>原子性：一个或者多个操作在 CPU 执行的过程中不被中断的特性。由于线程的切换，导致多个线程同时执行同一段代码，带来的原子性问题。</p> <p>可见性：一个线程对共享变量的修改，另外一个线程能够立刻看到。缓存不能及时刷新导致了可见性问题。</p> <p>有序性：程序执行的顺序按照代码的先后顺序执行。编译器为了优化性能而改变程序中语句的先后顺序，导致有序性问题。</p> <p>启发：线程的切换、缓存及编译优化都是为了提高性能，但是引发了并发编程的问题。这也告诉我们技术在解决一个问题时，必然会带来另一个问题，需要我们提前考虑新技术带来的问题以规避风险。</p> <div class="custom-block tip"><p class="custom-block-title">来源</p> <p>来源： <a href="https://mp.weixin.qq.com/s?__biz=MzAxMjEwMzQ5MA==&amp;mid=2448888446&amp;idx=2&amp;sn=2d341878615e238eb572e855199b9a7e&amp;scene=21#wechat_redirect" target="_blank" rel="noopener noreferrer">java进阶架构师<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></div></div></div> <!----> <div class="page-edit"><!----> <div class="tags"><a href="/tags/?tag=%E5%B9%B6%E5%8F%91%E5%A4%9A%E7%BA%BF%E7%A8%8B" title="标签">#并发多线程</a></div> <!----></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><!----> <a href="/pages/f94dea/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">深入理解线程池</div></a></div> <div class="page-nav"><p class="inner"><!----> <span class="next"><a href="/pages/f94dea/">深入理解线程池</a>→
      </span></p></div></div></div> <!----></main></div> <div class="footer"><div class="icons"><a href="mailto:likanjia@126.com" title="发邮件" target="_blank" class="iconfont icon-youjian"></a><a href="https://github.com/" title="GitHub" target="_blank" class="iconfont icon-github"></a><a href="https://music.163.com/#/playlist?id=755597173" title="听音乐" target="_blank" class="iconfont icon-erji"></a></div> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2019-2023
    <span>likanjie | MIT License</span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <!----> <!----> <!----></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.c5f14b06.js" defer></script><script src="/assets/js/2.0bb8723e.js" defer></script><script src="/assets/js/8.165e4749.js" defer></script>
  </body>
</html>
